using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Oops.Xna.Framework.Audio;
using Oops.Xna.Framework.Input;
using Oops.Xna.Framework.UI;

namespace Oops.Xna.Framework.GameState
{
	/// <summary>
	/// A game component that represents a screen in a game
	/// </summary>
	/// <remarks>
	/// A <see cref="GameScreen"/> can be considered a sub-game.  It has it's own 
	/// <see cref="Microsoft.Xna.Framework.IGameComponent"/> collection, <see cref="Microsoft.Xna.Framework.Content.ContentManager"/>,
	/// and service collection, just like the <see cref="Microsoft.Xna.Framework.Game"/> class.
	/// </remarks>
	public class GameScreen : CompositeGameComponent<IGameComponent>
	{
		private string name;
		
		private ContentManager content;

		private IGameStateService gameStateService;
		private IInputService inputService;
		private IAudioService audioService;
		private IScreenSpaceService screenSpaceService;

		private GameScreenServiceContainer services;

		/// <summary>
		/// Initializes a new instance of the <see cref="GameScreen"/> class.
		/// </summary>
		/// <param name="game">The associated <see cref="Microsoft.Xna.Framework.Game"/>.</param>
		/// <param name="name">The name of the <see cref="GameScreen"/>.</param>
		public GameScreen(Game game, string name) : base(game)
		{
			// The name parameter must be specified.
			if (String.IsNullOrEmpty(name))
			{
				throw new ArgumentNullException("name");
			}

			// The game parameter must exist.
			if (game == null)
			{
				throw new ArgumentNullException("game");
			}

			// Hold onto parameters.
			this.name = name;

			// Create the service container for screen-specific services.
			this.services = new GameScreenServiceContainer(game.Services);

			// Create the content manager.
			this.content = new ContentManager(this.services, this.Game.Content.RootDirectory);
		}

		/// <summary>
		/// Gets the name of this <see cref="GameScreen"/>.
		/// </summary>
		public string Name
		{
			get { return this.name; }
		}

		/// <summary>
		/// Gets the associated <see cref="Microsoft.Xna.Framework.Content.ContentManager"/> of the <see cref="GameScreen"/>.
		/// </summary>
		public ContentManager Content
		{
			get { return this.content; }
		}

		/// <summary>
		/// Gets the <see cref="IGameStateService"/> that owns the <see cref="GameScreen"/>.
		/// </summary>
		protected IGameStateService GameStateService
		{
			get { return this.gameStateService; }
		}

		/// <summary>
		/// Gets the <see cref="IInputService"/> in context for the <see cref="GameScreen"/>.
		/// </summary>
		protected IInputService InputService
		{
			get { return this.inputService; }
		}

		/// <summary>
		/// Gets the <see cref="IAudioService"/> in context for the <see cref="GameScreen"/>.
		/// </summary>
		protected IAudioService AudioService
		{
			get { return this.audioService; }
		}

		/// <summary>
		/// Gets the <see cref="IScreenSpaceService"/> in context for the <see cref="GameScreen"/>.
		/// </summary>
		protected IScreenSpaceService ScreenSpaceService
		{
			get { return this.screenSpaceService; }
		}

		/// <summary>
		/// Gets the GameServiceContainer holding all the service providers attached
		/// to the Game.
		/// </summary>
		public GameScreenServiceContainer Services
		{
			get { return this.services; }
		}

		/// <summary>
		/// The <see cref="GameScreen"/> is becoming active.
		/// </summary>
		/// <param name="gameTime">Time elapsed since the last call to <see cref="Microsoft.Xna.Framework.GameComponent.Update(Microsoft.Xna.Framework.GameTime)"/>.</param>
		/// <param name="previousScreen">The active <see cref="GameScreen"/> before this one became active.</param>
		public virtual void Enter(GameTime gameTime, ref GameScreen previousScreen) { }

		/// <summary>
		/// The <see cref="GameScreen"/> is becoming inactive.
		/// </summary>
		/// <param name="gameTime">Time elapsed since the last call to <see cref="Microsoft.Xna.Framework.GameComponent.Update(Microsoft.Xna.Framework.GameTime)"/>.</param>
		public virtual void Exit(GameTime gameTime) { }

		/// <summary>
		/// Determines if the <see cref="GameStateComponent"/> should switch to a new <see cref="GameScreen"/>.
		/// </summary>
		/// <param name="gameTime">Time elapsed since the last call to <see cref="Microsoft.Xna.Framework.GameComponent.Update(Microsoft.Xna.Framework.GameTime)"/>.</param>
		/// <param name="newScreen">The <see cref="GameScreen"/> to switch to.</param>
		/// <returns>
		/// Returns <c>true</c> if the <see cref="GameScreen"/> should be updated and if
		/// a switch to a new <see cref="GameScreen"/>, if specified, should occur.
		/// </returns>
		public virtual bool GetTransition(GameTime gameTime, ref GameScreen newScreen)
		{
			// Always update.
			return true;
		}

		#region IGameComponent

		public override void Initialize()
		{
			// Get the required game services.
			this.gameStateService = this.Game.GetService<IGameStateService>();
			this.inputService = this.Game.GetService<IInputService>();
			this.audioService = this.Game.GetService<IAudioService>();
			this.screenSpaceService = this.Game.GetService<IScreenSpaceService>();

			// Call inherited method.
			base.Initialize();
		}

		#endregion

		internal new void UnloadContent()
		{
			// Call the protected overloaded method.
			base.UnloadContent();
		}
	}
}